package demo.java.mail;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.mail.Address;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeUtility;

import com.sun.mail.imap.IMAPFolder;
import com.sun.mail.imap.IMAPMessage;

public class MailServiceImpl {

	public void receiverMail(PROTOCOL protocol) throws Exception {
		Session config = getSession(protocol);
		config.setDebug(false);
		Store store = config.getStore(protocol.toString());
		store.connect();
		Folder folder = store.getFolder("website_monitor");
		folder.open(Folder.READ_ONLY);

		if (folder instanceof IMAPFolder) {
			MailContent mContent = new MailContent();
			// get all email
			Message[] emails = folder.getMessages();
			for (Message email : emails) {
				if (email instanceof IMAPMessage) {
					mContent.setSubject(this.getSubject(email));
					mContent.setFrom(this.getFrom(email));
					mContent.setTo(this.getReceiveAddress(email, RecipientType.TO));
					mContent.setCc(this.getReceiveAddress(email, RecipientType.CC));
					mContent.setBcc(this.getReceiveAddress(email, RecipientType.BCC));
					mContent.setSentDate(this.getSentDate(email, null));
					mContent.setSeen(this.isSeen(email));
					mContent.setReplySign(this.isReplySign(email));
					mContent.setSize(this.getSize(email));
					StringBuffer content = new StringBuffer();
					this.getMailContent(email, content);
					mContent.setContent(content.toString());
					System.out.println(mContent);
				}
				break;
			}
		}

		folder.close(false);
		store.close();

	}

	private Session getSession(final PROTOCOL protocol) throws Exception {
		Properties props = new Properties();
		
		/* config for imap */
		props.put("mail.imap.host", protocol.getHost());
		props.put("mail.imap.port", protocol.getPort());
		props.put("mail.store.protocol", protocol.toString());
		props.put("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
		props.put("mail.imap.socketFactory.port", protocol.getPort());
		props.put("mail.imap.socketFactory.fallback", "false");
		props.put("mail.imap.auth.login.disable", "true");
		props.put("mail.imap.ssl.enable", "true");
		
		/* config for pop3 */
        props.put("mail.store.protocol", protocol.toString());
        props.put("mail.pop3.port", protocol.getPort());
        props.put("mail.pop3.host", protocol.getHost());
        props.put("mail.pop3.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        props.put("mail.pop3.socketFactory.port", protocol.getPort());
        props.put("mail.pop3.socketFactory.fallback", "false");
        props.put("mail.pop3.auth.login.disable", "true");
        props.put("mail.pop3.ssl.enable", "true");

		return Session.getInstance(props, new Authenticator() {
			@Override
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(protocol.getEmail(), protocol.getPassword());
			}
		});
	}

	private String getSubject(Message email) {
		try {
			return MimeUtility.decodeText(email.getSubject());
		} catch (Exception e) {
			return "";
		}
	}

	private String getFrom(Message email) {
		try {
			for (Address addr : email.getFrom()) {
				InternetAddress iAddr = (InternetAddress) addr;
				return MimeUtility.decodeText(iAddr.getPersonal()) + "<" + iAddr.getAddress() + ">";
			}
		} catch (Exception e) {
			// Don't worries.
		}
		return "";
	}

	/**
	 * 根据收件人类型，获取邮件收件人、抄送和密送地址。如果收件人类型为空，则获得所有的收件人
	 * <p>
	 * Message.RecipientType.TO 收件人
	 * </p>
	 * <p>
	 * Message.RecipientType.CC 抄送
	 * </p>
	 * <p>
	 * Message.RecipientType.BCC 密送
	 * </p>
	 * 
	 * @param email
	 *            邮件内容
	 * @param type
	 *            收件人类型
	 * @return 邮件地址列表
	 */
	private List<String> getReceiveAddress(Message email, Message.RecipientType type) {
		List<String> address = new ArrayList<String>();
		try {
			for (Address addr : email.getRecipients(type)) {
				InternetAddress iAddr = (InternetAddress) addr;
				address.add(MimeUtility.decodeText(iAddr.getPersonal()) + "<" + iAddr.getAddress() + ">");
			}
		} catch (Exception e) {
			// Don't worries.
		}
		return address;
	}

	private String getSentDate(Message email, String pattern) throws Exception {
		if (null == pattern || pattern.trim().length() <= 0) {
			pattern = "yyy-MM-dd HH:mm:ss";

		}
		return new SimpleDateFormat(pattern).format(email.getSentDate());

	}

	public boolean isSeen(Message email) throws MessagingException {
		return email.getFlags().contains(Flags.Flag.SEEN);
	}

	public boolean isReplySign(Message email) throws MessagingException {
		return null == email.getHeader("Disposition-Notification-To") ? false : true;
	}

	private int getSize(Message email) throws Exception {
		return email.getSize();
	}

	public void getMailContent(Part part, StringBuffer content) throws MessagingException, IOException {

		boolean isContainTextAttach = part.getContentType().indexOf("name") > 0;

		if (part.isMimeType("text/*") && !isContainTextAttach) {
			content.append(part.getContent().toString());
		} else if (part.isMimeType("message/rfc822")) {
			getMailContent((Part) part.getContent(), content);
		} else if (part.isMimeType("multipart/*")) {
			Multipart multipart = (Multipart) part.getContent();
			int partCount = multipart.getCount();
			for (int i = 0; i < partCount; i++) {
				BodyPart bodyPart = multipart.getBodyPart(i);
				getMailContent(bodyPart, content);
			}
		}
	}

	public static void main(String[] args) throws Exception {
//		new MailServiceImpl().receiverMail(PROTOCOL.pop3);
		new MailServiceImpl().receiverMail(PROTOCOL.imap);
	}
}
